﻿using SuperX.Common.Log;
using SuperX.Helper.ServiceResponse;
using SuperX.SuperSocket.Common;
using SuperX.SuperSocket.Extensions;
using SuperSocket.ClientEngine;
using System;
using System.Collections.Generic;
using System.Net;
using System.Text;
using System.Threading;
using ErrorEventArgs = SuperSocket.ClientEngine.ErrorEventArgs;
using SuperX.Common.Helper;

namespace SuperX.SuperSocket.Client.Communication
{
    public class CommunicationEngine : IDisposable
    {
        internal AutoResetEvent m_OpenedEvent = new AutoResetEvent(false);

        private AutoResetEvent ExecutionStatus = new AutoResetEvent(false);

        private string Value;

        protected IClientCommandReader<TransferCommandInfo> CommandReader { get; private set; }

        private Dictionary<string, ICommand<CommunicationEngine, TransferCommandInfo>> m_CommandDict = new Dictionary<string, ICommand<CommunicationEngine, TransferCommandInfo>>(StringComparer.OrdinalIgnoreCase);

        internal TcpClientSession Client;

        internal EndPoint Endpoint;

        private string _Ip;

        private int _Port;

        public CommunicationEngine(string ip, int port)
        {
            _Ip = ip;
            _Port = port;
            Init();
        }

        public void Init()
        {
            try
            {
                Endpoint = new IPEndPoint(IPAddress.Parse(_Ip), _Port);
                UpLoadCommandBase[] baseArray = new UpLoadCommandBase[] { };
                foreach (UpLoadCommandBase base2 in baseArray)
                {
                    m_CommandDict.Add(base2.Name, base2);
                }
                Connect();
                CommandReader = new CommunicationReader(this);
            }
            catch (Exception e)
            {
                Logger.ErrorException(e);
            }
        }

        /// <summary>
        /// 连接服务器
        /// </summary>
        public void Connect()
        {
            TcpClientSession session = new AsyncTcpSession();
            session.Error += new EventHandler<ErrorEventArgs>(client_Error);
            session.DataReceived += new EventHandler<DataEventArgs>(client_DataReceived);
            session.Connected += new EventHandler(client_Connected);
            session.Closed += new EventHandler(client_Closed);
            Client = session;
            Client.Connect(Endpoint);
            if (!m_OpenedEvent.WaitOne(5000))
                Logger.Error("Client：SuperSocket连接失败，请检查服务器！！");
            else if (Client.IsConnected)
                Logger.Info("Client：连接成功！");

        }

        private void m_OnDataReceived(byte[] data, int offset, int length)
        {
            while (true)
            {
                if (CommandReader == null)
                    return;
                int num;
                TransferCommandInfo commandInfo = CommandReader.GetCommandInfo(data, offset, length, out num);
                if (CommandReader.NextCommandReader != null)
                {
                    CommandReader = CommandReader.NextCommandReader;
                }
                if (commandInfo != null)
                {
                    ExecuteCommand(commandInfo);
                }
                if (num <= 0)
                {
                    return;
                }
                offset = offset + length - num;
                length = num;
            }
        }

        private void ExecuteCommand(TransferCommandInfo commandInfo)
        {
            Extensions.ICommand<CommunicationEngine, TransferCommandInfo> command;
            if (m_CommandDict.TryGetValue(commandInfo.Key, out command))
            {
                command.ExecuteCommand(this, commandInfo);
            }
        }

        internal void SendData(Tag opCode, byte[] data, int offset, int length)
        {
            byte[] senddata = new byte[length + 5];
            senddata[0] = 0;
            senddata[1] = (byte)((int)opCode / 256);
            senddata[2] = (byte)((int)opCode % 256);
            senddata[3] = (byte)(length / 256);
            senddata[4] = (byte)(length % 256);
            Buffer.BlockCopy(data, offset, senddata, 5, length);
            Client.Send(senddata, 0, senddata.Length);
        }

        internal string SendMessage(string msg, Tag opCode = Tag.Receiving)
        {
            Value = null;
            ExecutionStatus.Reset();
            byte[] bytes = Encoding.UTF8.GetBytes(msg);
            SendData(opCode, bytes, 0, bytes.Length);
            if (!ExecutionStatus.WaitOne(5000))
            {
                Logger.Error("Client：通讯超时");
                return JsonHelper.TransferObjectJsonSerialize(ApiResponse<object>.Fail("通讯超时！"), false);
            }
            return Value;
        }

        private void client_Closed(object sender, EventArgs e)
        {
            Dispose();
        }

        private void client_Connected(object sender, EventArgs e)
        {
            m_OpenedEvent.Set();
        }

        private void client_DataReceived(object sender, DataEventArgs e)
        {

            byte[] dst = new byte[e.Length];
            Buffer.BlockCopy(e.Data, 0, dst, 0, e.Length);
            Value = Encoding.UTF8.GetString(dst);
            //m_OnDataReceived(e.Data, e.Offset, e.Length);
            ExecutionStatus.Set();
        }

        private void client_Error(object sender, ErrorEventArgs e)
        {

        }

        public void Dispose()
        {
            TcpClientSession client = Client;
            if (client != null)
            {
                client.Error -= new EventHandler<ErrorEventArgs>(client_Error);
                client.DataReceived -= new EventHandler<DataEventArgs>(client_DataReceived);
                client.Connected -= new EventHandler(client_Connected);
                client.Closed -= new EventHandler(client_Closed);
                if (client.IsConnected)
                {
                    client.Close();
                }
                Client = null;
            }
            CommandReader = null;
            m_CommandDict.Clear();
            m_OpenedEvent.Reset();
        }
    }
}
